Add user identity list NATS subject#31
Conversation
Implement a new ListIdentities handler that retrieves all linked identities for an authenticated user. This includes: - New NATS subject `lfx.auth-service.user_identity.list` - ListIdentities handler with auth token validation and identity mapping to a UI-friendly response format (provider, user_id, isSocial, profileData) - Auth0 user model conversion now populates Identity data - Comprehensive test coverage for success and error paths - Updated identity linking documentation with list operation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Fayaz G. <5818912+fayazg@users.noreply.github.com>
WalkthroughThis PR adds user identity listing functionality to the authentication service. It introduces a new NATS subject for identity listing, updates message routing and NATS subscriptions, extends domain interfaces, enriches Auth0 user model conversion to include identity data, implements the listing orchestrator logic, and provides comprehensive documentation and test coverage. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant MessageRouter as Message Router
participant Orchestrator as ListIdentities Handler
participant MetadataService as Metadata Service
participant UserReader as User Reader
participant Auth0Converter as Auth0 Model
Client->>MessageRouter: NATS request (auth_token)
MessageRouter->>Orchestrator: route to ListIdentities
Orchestrator->>Orchestrator: unmarshal & validate auth_token
Orchestrator->>MetadataService: MetadataLookup(token)
MetadataService-->>Orchestrator: metadata
Orchestrator->>UserReader: GetUser(user_id)
UserReader->>Auth0Converter: ToUser() with Identities
Auth0Converter-->>UserReader: User with Identities[]
UserReader-->>Orchestrator: full user record
Orchestrator->>Orchestrator: transform to identityResponse array
Orchestrator-->>Client: UserDataResponse (Success + Identities)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Pull request overview
Adds a new read-only NATS request/reply subject to list linked identities for the authenticated user (needed by the UI profile page), and fixes Auth0 user conversion so linked identities are no longer dropped.
Changes:
- Introduces
lfx.auth-service.user_identity.listsubject + routes/subscribes it through the server. - Implements
ListIdentitiesmessage handler and adds unit tests for success/error scenarios. - Fixes Auth0
ToUser()to mapIdentitiesinto the domainmodel.User.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/constants/subjects.go | Adds a new NATS subject constant for identity listing. |
| internal/domain/port/message_handler.go | Extends the message handler port with ListIdentities. |
| internal/service/message_handler.go | Implements ListIdentities handler + response DTOs. |
| internal/service/message_handler_test.go | Adds orchestrator unit tests for the new handler. |
| internal/infrastructure/auth0/models.go | Fixes Auth0User.ToUser() to include mapped identities. |
| cmd/server/service/message_handler.go | Routes the new subject to the orchestrator handler. |
| cmd/server/service/providers.go | Registers the new subject subscription. |
| docs/identity_linking.md | Documents the new list-identities subject and payload/response format. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| Email: id.Email, | ||
| EmailVerified: true, |
There was a problem hiding this comment.
ListIdentities sets email_verified to true whenever an identity has a non-empty email, but there’s no source-of-truth for verification status in model.Identity (only Email is stored). This can return incorrect data (e.g., for unverified provider emails) and makes the response misleading. Consider either omitting email_verified entirely (don’t set it so it’s omitted via omitempty), or extending the domain identity model to carry verification status (populated from Auth0 profileData.email_verified) and mapping that through.
| Email: id.Email, | |
| EmailVerified: true, | |
| Email: id.Email, |
| var identities []model.Identity | ||
| for _, auth0Id := range u.Identities { | ||
| identity := model.Identity{ | ||
| Provider: auth0Id.Provider, | ||
| IdentityID: fmt.Sprintf("%v", auth0Id.UserID), | ||
| IsSocial: auth0Id.IsSocial, | ||
| } | ||
| if auth0Id.ProfileData != nil { | ||
| identity.Email = auth0Id.ProfileData.Email | ||
| } | ||
| identities = append(identities, identity) | ||
| } |
There was a problem hiding this comment.
The new ToUser() mapping now includes Identities, but there’s no unit test covering this conversion (including edge cases like non-string Auth0Identity.UserID and presence/absence of profileData). Since this is a regression-prone mapping that impacts the new user_identity.list behavior, add a focused test around Auth0User.ToUser() to assert identities are populated and correctly converted.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
docs/identity_linking.md (1)
155-155:⚠️ Potential issue | 🟡 MinorStale documentation: identity listing subject now exists.
This line states "there is no dedicated subject for listing identities at this time," but this PR adds exactly that capability via
lfx.auth-service.user_identity.list. Please update this text to reference the new subject.📝 Suggested update
-- `unlink.identity_id`: The identity's ID as returned by the identity provider. This must be retrieved directly from the identity provider since there is no dedicated subject for listing identities at this time. ++ `unlink.identity_id`: The identity's ID as returned by the identity provider. This can be retrieved via the `lfx.auth-service.user_identity.list` subject (see [List Identities](`#list-identities`)).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/identity_linking.md` at line 155, The documentation line that claims "there is no dedicated subject for listing identities at this time" is now stale—replace that sentence to mention the new subject lfx.auth-service.user_identity.list and explain that unlink.identity_id can alternatively be retrieved via that subject (or show how to use lfx.auth-service.user_identity.list to list identities for a user). Update the text around unlink.identity_id to reference lfx.auth-service.user_identity.list as the dedicated identity-listing subject and, if appropriate, add a short note on expected request/response semantics.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@internal/service/message_handler.go`:
- Around line 293-298: The code currently hardcodes EmailVerified=true in
identityProfileData inside message_handler.go because model.Identity lacks an
EmailVerified field; update model.Identity to include EmailVerified bool,
propagate that value when building identities from Auth0 (use
Auth0ProfileData.EmailVerified in authelia/user.go) and in mock identities
(mock/user.go), and then change the message_handler.go block that sets
resp.ProfileData to use id.EmailVerified instead of true (or omit the field when
unknown). Ensure constructors and tests are updated to set or default
EmailVerified appropriately.
---
Outside diff comments:
In `@docs/identity_linking.md`:
- Line 155: The documentation line that claims "there is no dedicated subject
for listing identities at this time" is now stale—replace that sentence to
mention the new subject lfx.auth-service.user_identity.list and explain that
unlink.identity_id can alternatively be retrieved via that subject (or show how
to use lfx.auth-service.user_identity.list to list identities for a user).
Update the text around unlink.identity_id to reference
lfx.auth-service.user_identity.list as the dedicated identity-listing subject
and, if appropriate, add a short note on expected request/response semantics.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: cf8973f7-8b70-4e38-9325-05d18b277284
📒 Files selected for processing (8)
cmd/server/service/message_handler.gocmd/server/service/providers.godocs/identity_linking.mdinternal/domain/port/message_handler.gointernal/infrastructure/auth0/models.gointernal/service/message_handler.gointernal/service/message_handler_test.gopkg/constants/subjects.go
| if id.Email != "" { | ||
| resp.ProfileData = &identityProfileData{ | ||
| Email: id.Email, | ||
| EmailVerified: true, | ||
| } | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if email_verified is used elsewhere in identity-related code
rg -n "email_verified|EmailVerified" --type=go -C2Repository: linuxfoundation/lfx-v2-auth-service
Length of output: 8651
🏁 Script executed:
# Find the model.Identity structure definition
fd -n "models\|identity" --type=go | grep -E "model|pkg" | head -20Repository: linuxfoundation/lfx-v2-auth-service
Length of output: 309
🏁 Script executed:
# Get full context around the problematic lines in message_handler.go
cat -n internal/service/message_handler.go | sed -n '280,310p'Repository: linuxfoundation/lfx-v2-auth-service
Length of output: 1024
🏁 Script executed:
# Search for model.Identity definition
rg -n "type Identity struct" --type=go -A 15Repository: linuxfoundation/lfx-v2-auth-service
Length of output: 1476
🏁 Script executed:
# Find where fullUser.Identities is populated
rg -n "Identities\s*=" --type=go -B 5 -A 5 | head -80Repository: linuxfoundation/lfx-v2-auth-service
Length of output: 4356
🏁 Script executed:
# Check how Auth0 identities are mapped to model.Identity
rg -n "model\.Identity|Identity{" --type=go -B 3 -A 3 | grep -A 8 -B 8 "Email"Repository: linuxfoundation/lfx-v2-auth-service
Length of output: 192
🏁 Script executed:
# Look at Auth0 integration to understand when emails are unverified
rg -n "EmailVerified.*false" --type=go -B 3 -A 3Repository: linuxfoundation/lfx-v2-auth-service
Length of output: 1739
🏁 Script executed:
# Check API endpoint that returns this data
rg -n "GetIdentities|identities\|email_verified" --type=go | head -40Repository: linuxfoundation/lfx-v2-auth-service
Length of output: 61
🏁 Script executed:
# Search for tests that verify the email_verified response field
rg -n "email_verified.*true|email_verified.*false" --type=go -B 3 -A 3Repository: linuxfoundation/lfx-v2-auth-service
Length of output: 519
EmailVerified hardcoded as true due to missing field in model.Identity.
The issue is real: Auth0ProfileData includes EmailVerified (which can be false for passwordless flows), but model.Identity lacks this field entirely. When identities are constructed in authelia/user.go and mock/user.go, the EmailVerified status is discarded. The response then hardcodes true for any identity with an email, misrepresenting unverified emails as verified.
Consider extending model.Identity to include EmailVerified and propagating it from Auth0, or omit email_verified from the response if accurate status cannot be provided.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@internal/service/message_handler.go` around lines 293 - 298, The code
currently hardcodes EmailVerified=true in identityProfileData inside
message_handler.go because model.Identity lacks an EmailVerified field; update
model.Identity to include EmailVerified bool, propagate that value when building
identities from Auth0 (use Auth0ProfileData.EmailVerified in authelia/user.go)
and in mock identities (mock/user.go), and then change the message_handler.go
block that sets resp.ProfileData to use id.EmailVerified instead of true (or
omit the field when unknown). Ensure constructors and tests are updated to set
or default EmailVerified appropriately.
Overview
Adds
lfx.auth-service.user_identity.list— a read-only NATS subject that returns all identities linked to a user account. This is required by the lfx-v2-ui profile page to display connected social oviders (GitHub, LinkedIn, Google, etc.).Also fixes a bug in Auth0's
ToUser()which was silently dropping theIdentitiesfield when converting from the Auth0 API response to the domain model.Changes
New handler —
ListIdentitiesininternal/service/message_handler.go{ "user": { "auth_token": "..." } }MetadataLookup, fetches user viaGetUserBug fix —
internal/infrastructure/auth0/models.goToUser()now convertsAuth0Identityslice →[]model.Identity(was previously ignored)Wiring — constant, port interface, routing, subscription all updated
Test evidence
Full suite:
go test ./...— all pass.Checklist
UserIdentityListSubjectconstant added (pkg/constants/subjects.go)ListIdentitiesadded toUserReaderHandlerinterface (internal/domain/port/message_handler.go)ListIdentitieshandler implemented with response DTO (internal/service/message_handler.go)ToUser()fixed to populateIdentities(internal/infrastructure/auth0/models.go)cmd/server/service/message_handler.gocmd/server/service/providers.gointernal/service/message_handler_test.go)docs/identity_linking.md)go test ./...)